﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Jungo.wdapi_dotnet;
using wdc_err = Jungo.wdapi_dotnet.WD_ERROR_CODES;
using item_types = Jungo.wdapi_dotnet.ITEM_TYPE;
using UINT64 = System.UInt64;
using UINT32 = System.UInt32;
using DWORD = System.UInt32;
using WORD = System.UInt16;
using BYTE = System.Byte;
using BOOL = System.Boolean;
using WDC_DEVICE_HANDLE = System.IntPtr;
using HANDLE = System.IntPtr;
namespace PciDeviceLib
{
    /* Kernel PlugIn version information struct */
    public struct KP_PCI_VERSION
    {
        public DWORD dwVer;
        public string cVer; //max size = 100
    };

    /* Kernel Plugin messages status */
    public enum KP_PCI_STATUS
    {
        KP_PCI_STATUS_OK = 0x1,
        KP_PCI_STATUS_MSG_NO_IMPL = 0x1000,
    };

    public enum KP_PCI_MSG
    {
        KP_PCI_MSG_VERSION = 1,
    };

    /* PCI diagnostics plug-and-play and power management events handler 
     * function type */
    public delegate void USER_EVENT_CALLBACK(ref WD_EVENT pEvent, PCI_Device dev);
    /* PCI diagnostics interrupt handler function type */
    public delegate void USER_INTERRUPT_CALLBACK(PCI_Device device);

    public class PCI_Device
    {
        private WDC_DEVICE m_wdcDevice = new WDC_DEVICE();
        protected MarshalWdcDevice m_wdcDeviceMarshaler;
        protected string m_sDeviceLongDesc;
        protected string m_sDeviceShortDesc;

        /* Kernel PlugIn driver name (should be no more than 8 characters) */
      //  private string m_sKP_PCI_DRIVER_NAME = "KP_PCI";

        #region " constructors " 
        /* constructors & destructors */

        internal protected PCI_Device(DWORD dwVendorId, DWORD dwDeviceId, WD_PCI_SLOT slot)
        {
            m_wdcDevice = new WDC_DEVICE();
            m_wdcDevice.id.pciId.dwVendorId = dwVendorId;
            m_wdcDevice.id.pciId.dwDeviceId = dwDeviceId;
            m_wdcDevice.slot.pciSlot = slot;
            m_wdcDeviceMarshaler = new MarshalWdcDevice();
            SetDescription();

        }

        public void Dispose()
        {
            Close();
        }
        #endregion

        #region " properties " 
        /*******************
        *  properties       *
        *******************/

        public IntPtr Handle
        {
            get
            {
                return m_wdcDevice.hDev;
            }
            set
            {
                m_wdcDevice.hDev = value;
            }
        }
        public WDC_ADDR_DESC[] AddrDesc
        {
            get
            {
                return m_wdcDevice.pAddrDesc;
            }
            set
            {
                m_wdcDevice.pAddrDesc = value;
            }
        }
        protected WDC_DEVICE wdcDevice
        {
            get
            {
                return m_wdcDevice;
            }
            set
            {
                m_wdcDevice = value;
            }
        }

        public WD_PCI_ID id
        {
            get
            {
                return m_wdcDevice.id.pciId;
            }
            set
            {
                m_wdcDevice.id.pciId = value;
            }
        }

        public WD_PCI_SLOT slot
        {
            get
            {
                return m_wdcDevice.slot.pciSlot;
            }
            set
            {
                m_wdcDevice.slot.pciSlot = value;
            }
        }


        #endregion


        #region " Device Open/Close " 
        /****************************
         *  Device Open & Close     *
         * **************************/

        /* public methods */
        public virtual DWORD Open()
        {
            DWORD dwStatus;
            WD_PCI_CARD_INFO deviceInfo = new WD_PCI_CARD_INFO();

            /* Retrieve the device's resources information */
            deviceInfo.pciSlot = slot;
            dwStatus = wdc_lib_decl.WDC_PciGetDeviceInfo(deviceInfo);
            if ((DWORD)wdc_err.WD_STATUS_SUCCESS != dwStatus)
            {

                return dwStatus;
            }

            /* NOTE: You can modify the device's resources information here, 
             * if necessary (mainly the deviceInfo.Card.Items array or the
             * items number - deviceInfo.Card.dwItems) in order to register
             * only some of the resources or register only a portion of a
             * specific address space, for example. */

            dwStatus = wdc_lib_decl.WDC_PciDeviceOpen(ref m_wdcDevice,
                deviceInfo, IntPtr.Zero, IntPtr.Zero, "", IntPtr.Zero);

            if ((DWORD)wdc_err.WD_STATUS_SUCCESS != dwStatus)
            {


                goto Error;
            }

            return (DWORD)wdc_err.WD_STATUS_SUCCESS;



        Error:
            if (Handle != IntPtr.Zero)
                Close();

            return dwStatus;
        }

        public virtual bool Close()
        {
            DWORD dwStatus;

            if (Handle == IntPtr.Zero)
            {

                return false;
            }



            /* Close the device */
            dwStatus = wdc_lib_decl.WDC_PciDeviceClose(Handle);
            if ((DWORD)wdc_err.WD_STATUS_SUCCESS != dwStatus)
            {

            }
            else
            {
                Handle = IntPtr.Zero;
            }

            return ((DWORD)wdc_err.WD_STATUS_SUCCESS == dwStatus);
        }

        #endregion
        public bool IsMySlot(ref WD_PCI_SLOT slot)
        {
            if (m_wdcDevice.slot.pciSlot.dwBus == slot.dwBus &&
                m_wdcDevice.slot.pciSlot.dwSlot == slot.dwSlot &&
                m_wdcDevice.slot.pciSlot.dwFunction == slot.dwFunction)
                return true;

            return false;
        }
        public string ToString(BOOL bLong)
        {
            return (bLong) ? m_sDeviceLongDesc : m_sDeviceShortDesc;
        }
        /* protected methods */

        protected void SetDescription()
        {
            m_sDeviceLongDesc = string.Format(" Device: VendorID 0x{0:X}, "
                + "DeviceID 0x{1:X}, 物理位置：总线{2:X}；设备{3:X}；功能{4:X}",
                id.dwVendorId, id.dwDeviceId, slot.dwBus, slot.dwSlot,
                slot.dwFunction);

            m_sDeviceLongDesc = string.Format(" Device: 供应商ID 0x{0:X}, "
          + "设备ID 0x{1:X}, 物理位置：总线{2:X}；设备{3:X}；功能{4:X}",
          id.dwVendorId, id.dwDeviceId, slot.dwBus, slot.dwSlot,
          slot.dwFunction);

            m_sDeviceShortDesc = string.Format("Device " +
                "{0:X},{1:X} {2:X}:{3:X}:{4:X}", id.dwVendorId,
                id.dwDeviceId, slot.dwBus, slot.dwSlot, slot.dwFunction);
        }

    }
}
